<template>
  <div class="scene-wrapper">
    <div class="scene-container" ref="container"></div>
  </div>
</template>

<script setup>
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { CSS2DRenderer, CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer.js'

const props = defineProps({
  alertType: {
    type: String,
    default: null
  },
  alertData: {
    type: Object,
    default: null
  }
})

const container = ref(null)
let renderer
let labelRenderer
let scene
let camera
let controls
let animationId
let alertMarker = null
let alertLabel = null

const createBlock = (width, height, depth, color) => {
  const geometry = new THREE.BoxGeometry(width, height, depth)
  const material = new THREE.MeshStandardMaterial({
    color,
    roughness: 0.3,
    metalness: 0.2,
    emissive: new THREE.Color(color).multiplyScalar(0.25)
  })
  return new THREE.Mesh(geometry, material)
}

const initScene = () => {
  const width = container.value.clientWidth
  const height = container.value.clientHeight

  renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })
  renderer.setPixelRatio(window.devicePixelRatio)
  renderer.setSize(width, height)
  renderer.shadowMap.enabled = true
  container.value.appendChild(renderer.domElement)

  // CSS2D标签渲染器
  labelRenderer = new CSS2DRenderer()
  labelRenderer.setSize(width, height)
  labelRenderer.domElement.style.position = 'absolute'
  labelRenderer.domElement.style.top = '0'
  labelRenderer.domElement.style.pointerEvents = 'none'
  container.value.appendChild(labelRenderer.domElement)

  scene = new THREE.Scene()
  scene.fog = new THREE.FogExp2(0x0a1a2e, 0.015)

  camera = new THREE.PerspectiveCamera(38, width / height, 1, 1000)
  camera.position.set(0, 50, 40) // 自然视角

  controls = new OrbitControls(camera, renderer.domElement)
  controls.enableDamping = true
  controls.enablePan = false
  controls.enableRotate = true
  controls.enableZoom = true
  controls.maxPolarAngle = Math.PI / 2.05
  controls.minDistance = 30
  controls.maxDistance = 80

  const ambientLight = new THREE.AmbientLight(0x4a9eff, 0.6)
  scene.add(ambientLight)

  const dirLight = new THREE.DirectionalLight(0x6bb6ff, 0.8)
  dirLight.position.set(25, 50, 20) // 自然光照
  dirLight.castShadow = true
  scene.add(dirLight)

  const plane = new THREE.Mesh(
    new THREE.PlaneGeometry(120, 80),
    new THREE.MeshStandardMaterial({
      color: 0x043054,
      metalness: 0.3,
      roughness: 0.8,
      transparent: true,
      opacity: 0.9
    })
  )
  plane.rotation.x = -Math.PI / 2
  plane.receiveShadow = true
  scene.add(plane)

  // 只创建堆放场模型
  const blockStorage = createBlock(48, 18, 26, 0x4caf50)
  blockStorage.position.set(0, 9, 0)
  blockStorage.castShadow = true
  scene.add(blockStorage)

  const gridHelper = new THREE.GridHelper(120, 12, 0x0b4b7f, 0x0b4b7f)
  scene.add(gridHelper)

  const animate = () => {
    controls.update()
    renderer.render(scene, camera)
    if (labelRenderer) {
      labelRenderer.render(scene, camera)
    }
    animationId = requestAnimationFrame(animate)
  }

  animate()
}

const createAlertMarker = (position, alertData) => {
  removeAlertMarker()
  if (!position || !alertData) return

  const geometry = new THREE.SphereGeometry(2, 16, 16)
  const material = new THREE.MeshStandardMaterial({
    color: 0xff4444,
    emissive: 0xff0000,
    emissiveIntensity: 0.8
  })
  alertMarker = new THREE.Mesh(geometry, material)
  alertMarker.position.set(position.x, position.y, position.z)
  scene.add(alertMarker)

  const labelDiv = document.createElement('div')
  labelDiv.className = 'alert-label-3d'
  labelDiv.innerHTML = `
    <div class="alert-label-content">
      <div class="alert-label-title">${alertData.message}</div>
      <div class="alert-label-time">${alertData.time}</div>
      <div class="alert-label-camera">${alertData.camera}</div>
    </div>
  `
  alertLabel = new CSS2DObject(labelDiv)
  alertLabel.position.set(position.x, position.y + 5, position.z) // 自然视角
  scene.add(alertLabel)

  let pulseScale = 1
  let pulseDirection = 1
  const pulseAnimate = () => {
    if (alertMarker) {
      pulseScale += pulseDirection * 0.02
      if (pulseScale > 1.3 || pulseScale < 0.7) {
        pulseDirection *= -1
      }
      alertMarker.scale.set(pulseScale, pulseScale, pulseScale)
      requestAnimationFrame(pulseAnimate)
    }
  }
  pulseAnimate()
}

const removeAlertMarker = () => {
  if (alertMarker) {
    scene.remove(alertMarker)
    alertMarker.geometry.dispose()
    alertMarker.material.dispose()
    alertMarker = null
  }
  if (alertLabel) {
    scene.remove(alertLabel)
    alertLabel = null
  }
}

watch(() => props.alertData, (newData) => {
  if (newData && newData.position) {
    createAlertMarker(newData.position, newData)
  } else {
    removeAlertMarker()
  }
}, { immediate: true })

const onResize = () => {
  if (!container.value || !renderer) return
  const width = container.value.clientWidth
  const height = container.value.clientHeight
  camera.aspect = width / height
  camera.updateProjectionMatrix()
  renderer.setSize(width, height)
  if (labelRenderer) {
    labelRenderer.setSize(width, height)
  }
}

onMounted(() => {
  initScene()
  window.addEventListener('resize', onResize)
})

onBeforeUnmount(() => {
  window.removeEventListener('resize', onResize)
  cancelAnimationFrame(animationId)
  removeAlertMarker()
  controls?.dispose()
  renderer?.dispose()
  labelRenderer?.domElement.remove()
  container.value?.replaceChildren()
})
</script>

<style scoped>
.scene-wrapper {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: 12px;
  border: 1px solid rgba(0, 235, 255, 0.25);
  background: rgba(3, 27, 52, 0.65);
  overflow: hidden;
  box-shadow: inset 0 0 50px rgba(0, 170, 255, 0.08);
}

.scene-container {
  width: 100%;
  height: 100%;
}
</style>
